import { readPackageJSON } from 'pkg-types';
import GenerateConfig from 'unplugin-config/vite';
import { type PluginOption } from 'vite';

import { getEnvConfig } from '../utils/env';
import { createContentHash, strToHex } from '../utils/hash';

const getVariableName = (title: string) => {
  function strToHex(str: string) {
    const result: string[] = [];
    for (let i = 0; i < str.length; ++i) {
      const hex = str.charCodeAt(i).toString(16);
      result.push(('000' + hex).slice(-4));
    }
    return result.join('').toUpperCase();
  }

  return `__PRODUCTION__${strToHex(title) || '__APP'}__CONF__`.toUpperCase().replace(/\s/g, '');
};

async function getConfigSource(appTitle: string) {
  const config = await getEnvConfig();
  const variableName = getVariableName(appTitle);
  const windowVariable = `window.${variableName}`;
  // Ensure that the variable will not be modified
  let source = `${windowVariable}=${JSON.stringify(config)};`;
  source += `
    Object.freeze(${windowVariable});
    Object.defineProperty(window, "${variableName}", {
      configurable: false,
      writable: false,
    });
  `.replace(/\s/g, '');
  return source;
}

const GLOBAL_CONFIG_FILE_NAME = '_app.config.js';
// This constant sets the output directory for the Vite package
const OUTPUT_DIR = 'dist';
export async function createConfigPluginConfig(
  shouldGenerateConfig: boolean,
): Promise<PluginOption> {
  const config = await getEnvConfig();

  let appTitle = config?.VITE_GLOB_APP_TITLE ?? '';

  appTitle = appTitle.replace(/\s/g, '_').replace(/-/g, '_');
  const source = await getConfigSource(appTitle);
  // LINK /src/utils/env.ts -> getVariableName
  const APP_NAME = strToHex(config?.VITE_GLOB_APP_TITLE ?? '__APP');
  const { version } = await readPackageJSON(process.cwd());

  // https://github.com/kirklin/unplugin-config
  return GenerateConfig({
    appName: APP_NAME,
    envVariables: {
      prefix: 'VITE_GLOB_',
    },
    configFile: {
      generate: shouldGenerateConfig,
      fileName: `${GLOBAL_CONFIG_FILE_NAME}?v=${version}-${createContentHash(source)}`,
      outputDir: OUTPUT_DIR,
    },
    htmlInjection: {
      decodeEntities: true,
    },
  });
}
